#include <fstream>
#include "../source/server.hpp"
#include <sys/stat.h>

size_t Split(const std::string &src, const std::string &sep, std::vector<std::string> *array)
{
    size_t offset = 0;          // 5
    while (offset < src.size()) // aa,b,
    {
        // 在src字符串偏移量offset出开始查找sep字符或子串，返回查找到的位置
        size_t pos = src.find(sep, offset); // 2
        if (pos == std::string::npos)       // 代表没有找到特定的字符
        {
            // 将剩余的部分当做一个子串，放入array中
            if (pos == src.size() - 1)
                break;
            array->push_back(src.substr(offset));
            return array->size();
        }
        // aaa,bbb,ccc,
        if (pos == offset) // 当前子串为空
        {
            offset = pos + sep.size();
            continue;
        }
        array->push_back(src.substr(offset, pos - offset));
        offset = pos + sep.size();
    }
    return array->size();
}

// int main()
// {
//     std::string str = "aa"; //"aa,"、"aa,,,,b,"
//     std::string sep = ",";
//     std::vector<std::string> array;
//     size_t ret = Split(str, sep, &array);
//     for (auto &s : array)
//     {
//         std::cout << "[" << s << "]" << std::endl;
//     }
//     std::cout << "子串数：" << ret << std::endl;
//     return 0;
// }

//  读取文件内容：将读取的内容放到一个buffer中
static bool ReadFile(const std::string &filename, std::string *buf)
{
    std::ifstream ifs(filename, std::ios::binary);
    if (ifs.is_open() == false)
    {
        ERR_LOG("OPEN %s FILE FAILED...", filename.c_str());
        return false;
    }
    int fsize = 0;
    ifs.seekg(0, ifs.end); // seekg跳转到末尾
    fsize = ifs.tellg();   // 获取到文件大小
    ifs.seekg(0, ifs.beg); // 跳转到起始位置

    std::string str;
    buf->resize(fsize);
    ifs.read(&(*buf)[0], fsize);
    if (ifs.good() == false)
    {
        ERR_LOG("READ %s FILE FAILED...", filename.c_str());
        ifs.close();
        return false;
    }
    ifs.close();
    return true;
}

// 向文件写入数据
static bool WriteFile(const std::string &filename, const std::string &buf)
{
    std::ofstream ofs(filename, std::ios::binary | std::ios::trunc);
    if (ofs.is_open() == false)
    {
        ERR_LOG("OPEN %s FILE FAILED...", filename.c_str());
        return false;
    }
    ofs.write(buf.c_str(), buf.size());
    if (ofs.good() == false)
    {
        ERR_LOG("WRITE %s FILE FAILED...", filename.c_str());
        ofs.close();
        return false;
    }
    ofs.close();
    return true;
}
static std::string UrlEncode(const std::string &url, bool convert_space_to_plus)
{
    std::string res;
    for (auto &c : url)
    {
        if (c == '.' || c == '-' || c == '_' || c == '~' || isalnum(c))
        {
            res += c;
            continue;
        }
        if (c == ' ' && convert_space_to_plus)
        {
            res += '+';
            continue;
        }

        // 剩下的字符都是需要编码成为 %HH 格式
        char tmp[4] = {0};
        // snprintf 与 printf比较类似，只不过，都是格式化字符，只不过一个是打印，一个是放到一块空间中
        snprintf(tmp, 4, "%%%02x", c);
        res += tmp;
    }
    return res;
}
static int HEXTOI(char c)
{
    if (c >= '0' && c <= '9')
    {
        return c - '0';
    }
    else if (c >= 'a' && c <= 'z')
    {
        return c - 'a' + 10;
    }
    else if (c >= 'A' && c <= 'Z')
    {
        return c - 'A' + 10;
    }
    return -1;
}
static std::string UrlDecode(const std::string &url, bool convert_space_to_plus)
{
    std::string res;
    for (int i = 0; i < url.size(); i++)
    {
        if (url[i] == '+' && convert_space_to_plus == true)
        {
            res += ' ';
            continue;
        }

        if (url[i] == '%' && (i + 2) < url.size())

        {
            char v1 = HEXTOI(url[i + 1]);
            char v2 = HEXTOI(url[i + 2]);
            char v = (v1 << 4) + v2;
            res += v;
            i += 2;
            continue;
        }
        res += url[i];
    }
    return res;
}

static std::string StatuDesc(int statu)
{
    std::unordered_map<int, std::string> _status_msg = {
        {100, "Continue"},
        {101, "Switching Protocols"},
        {102, "Processing"},
        {200, "OK"},
        {201, "Created"},
        {202, "Accepted"},
        {203, "Non-Authoritative Information"},
        {204, "No Content"},
        {205, "Reset Content"},
        {206, "Partial Content"},
        {207, "Multi-Status"},
        {300, "Multiple Choices"},
        {301, "Moved Permanently"},
        {302, "Move Temporarily"},
        {303, "See Other"},
        {304, "Not Modified"},
        {305, "Use Proxy"},
        {306, "Switch Proxy"},
        {307, "Temporary Redirect"},
        {400, "Bad Request"},
        {401, "Unauthorized"},
        {402, "Payment Required"},
        {403, "Forbidden"},
        {404, "Not Found"},
        {405, "Method Not Allowed"},
        {406, "Not Acceptable"},
        {407, "Proxy Authentication Required"},
        {408, "Request Time-out"},
        {409, "Conflict"},
        {410, "Gone"},
        {411, "Length Required"},
        {412, "Precondition Failed"},
        {413, "Request Entity Too Large"},
        {414, "Request-URI Too Large"},
        {415, "Unsupported Media Type"},
        {416, "Requested range not satisfiable"},
        {417, "Expectation Failed"},
        {418, "I'm a teapot"},
        {421, "Misdirected Request"},
        {422, "Unprocessable Entity"},
        {423, "Locked"},
        {424, "Failed Dependency"},
        {425, "Too Early"},
        {426, "Upgrade Required"},
        {449, "Retry With"},
        {451, "Unavailable For Legal Reasons"},
        {500, "Internal Server Error"},
        {501, "Not Implemented"},
        {502, "Bad Gateway"},
        {503, "Service Unavailable"},
        {504, "Gateway Timeout"},
        {505, "HTTP Version Not Supported"},
        {506, "Variant Also Negotiates"},
        {507, "Insufficient Storage"},
        {509, "Bandwidth Limit Exceeded"},
        {510, "Not Extended"},
        {600, "Unparseable Response Headers"}};
    auto it = _status_msg.find(statu);
    if (it != _status_msg.end())
    {
        return it->second;
    }
    return "unknown";
}

static std::string ExtMime(const std::string &filename)
{
    std::unordered_map<std::string, std::string> _mime_msg = {
        {".aac", "audio/aac"},
        {".abw", "application/x-abiword"},
        {".arc", "application/x-freearc"},
        {".avi", "video/x-msvideo"},
        {".azw", "application/vnd.amazon.ebook"},
        {".bin", "application/octet-stream"},
        {".bmp", "image/bmp"},
        {".bz", "application/x-bzip"},
        {".bz2", "application/x-bzip2"},
        {".csh", "application/x-csh"},
        {".css", "text/css"},
        {".csv", "text/csv"},
        {".doc", "application/msword"},
        {".docx", "application/vnd.openxmlformats-officedocument.wordprocessingml.document"},
        {".eot", "application/vnd.ms-fontobject"},
        {".epub", "application/epub+zip"},
        {".gif", "image/gif"},
        {".htm", "text/html"},
        {".html", "text/html"},
        {".ico", "image/vnd.microsoft.icon"},
        {".ics", "text/calendar"},
        {".jar", "application/java-archive"},
        {".jpeg", "image/jpeg"},
        {".jpg", "image/jpeg"},
        {".js", "text/javascript"},
        {".json", "application/json"},
        {".jsonld", "application/ld+json"},
        {".mid", "audio/midi"},
        {".midi", "audio/x-midi"},
        {".mjs", "text/javascript"},
        {".mp3", "audio/mpeg"},
        {".mp4", "video/mp4"},
        {".mpeg", "video/mpeg"},
        {".mpkg", "application/vnd.apple.installer+xml"},
        {".odp", "application/vnd.oasis.opendocument.presentation"},
        {".ods", "application/vnd.oasis.opendocument.spreadsheet"},
        {".odt", "application/vnd.oasis.opendocument.text"},
        {".oga", "audio/ogg"},
        {".ogv", "video/ogg"},
        {".ogx", "application/ogg"},
        {".opus", "audio/opus"},
        {".otf", "font/otf"},
        {".png", "image/png"},
        {".pdf", "application/pdf"},
        {".php", "application/x-httpd-php"},
        {".ppt", "application/vnd.ms-powerpoint"},
        {".pptx", "application/vnd.openxmlformats-officedocument.presentationml.presentation"},
        {".rar", "application/vnd.rar"},
        {".rtf", "application/rtf"},
        {".sh", "application/x-sh"},
        {".svg", "image/svg+xml"},
        {".tar", "application/x-tar"},
        {".tif", "image/tiff"},
        {".tiff", "image/tiff"},
        {".ts", "video/mp2t"},
        {".ttf", "font/ttf"},
        {".txt", "text/plain"},
        {".vsd", "application/vnd.visio"},
        {".wav", "audio/wav"},
        {".weba", "audio/webm"},
        {".webm", "video/webm"},
        {".webp", "image/webp"},
        {".woff", "font/woff"},
        {".woff2", "font/woff2"},
        {".xhtml", "application/xhtml+xml"},
        {".xls", "application/vnd.ms-excel"},
        {".xlsx", "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"},
        {".xml", "application/xml"},
        {".xul", "application/vnd.mozilla.xul+xml"},
        {".zip", "application/zip"},
        {".3gp", "video/3gpp"},
        {".3g2", "video/3gpp2"},
        {".7z", "application/x-7z-compressed"}};
    // 取出文件扩展名
    // a.b.txt
    size_t pos = filename.find_last_of('.');
    if (pos == std::string::npos)
    {
        return "application/octet-stream";
    }
    // 根据扩展名， 获取mime
    std::string ext = filename.substr(pos);
    auto it = _mime_msg.find(ext);
    if (pos == std::string::npos)
    {
        return "application/octet-stream";
    }
    return it->second;
}

// 判断一个文件是否是一个目录
static bool IsDirectory(const std::string &filename)
{
    struct stat st;
    int ret = stat(filename.c_str(), &st);
    if (ret < 0)
    {
        return false;
    }
    return S_ISDIR(st.st_mode);
}
// 判断一个文件时否是一个普通文件
static bool IsRegulerFile(const std::string &filename)
{
    struct stat st;
    int ret = stat(filename.c_str(), &st);
    if (ret < 0)
    {
        return false;
    }
    return S_ISREG(st.st_mode);
}
static bool ValidPath(const std::string &path)
{
    // 思想：计算目录深度，按照斜杠进行路径分割，根据有多少子目录(有多少层)，深度不能少于0
    std::vector<std::string> subdir;
    Split(path, "/", &subdir);
    int level = 0;

    for (auto &dir : subdir)
    {
        if (dir == "..")
        {
            level--; // 任意一层走出相对根目录，就认为有问题
            if (level < 0)
            {
                return false;
            }
            continue;
        }
        level++;
    }
    return true;
}
int main()
{
    // std::string res = StatuDesc(400);
    // std::cout << res << std::endl;
    // std::string res1 = ExtMime("regex.txt");
    // std::cout << res1 << std::endl;
    // std::cout << IsDirectory("http.txt") << std::endl;
    // std::cout << IsRegulerFile("http/") << std::endl;
    std::cout << ValidPath("/example") << std::endl;
    // std::string str = "C  ";
    // std::string res = UrlEncode(str, true);
    // std::cout << res << std::endl;
    // std::string res1 = UrlDecode(res, true);
    // std::cout << res1 << std::endl;

    // std::string buf;
    // bool ret = ReadFile("eventfd.cpp", &buf);
    // if (ret == false)
    // {
    //     return 1;
    // }
    // ret = WriteFile("./HAHA.txt", buf);
    // if (ret == false)
    // {
    //     return 1;
    // }
    // std::cout << buf << std::endl;

    return 0;
}